home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / COMM / ANSI_133 / PINGANSI.PAS < prev    next >
Pascal/Delphi Source File  |  1990-08-22  |  17KB  |  543 lines

  1. {$Define TurboPower}{ use Turbo Power Professional }
  2. {$Define Music} { implement 'ansi'-music }
  3. {$Define BBS} { enable support for bbs/communication usage }
  4. {$UnDef Small} { enable i/o driver }
  5. { $A+,B-,D-,E-,F+,I-,L-,O+,R-,S-,V-}
  6. (*
  7.      PingAnsi v 1.33 (c) CopyRight 1990 P.H.Rankin Hansen.
  8.  
  9.      This unit provides partial Ansi emulation for Turbo Pascal versions
  10.      5.x and higher.  (version 4 does  not implement  procedural types).
  11.      Some routines may be handled in a non-standard way.
  12.  
  13.      Released in Denmark on August 23rd 1990.
  14.  
  15.      By  using  this  material  You  assume  FULL responsibility for ANY
  16.      consequences  -  direct  or   indirect  -  thereof.
  17.      Any dispute regarding this material shall be setteled by Danish law
  18.      and in a Danish Court.
  19.  
  20.      (Sigh!)
  21.  
  22.      This  source may  NOT be  used by  Lawyers, Politicians or  persons
  23.      engaged  in any  other form  of terrorism.  Otherwise the  usage is
  24.      free.
  25.  
  26.      This source may be freely distributed as long as no fee is charged.
  27.  
  28.      Please direct any comments,  corrections, modifications via netmail
  29.      to:
  30.  
  31.                       Ping Hansen - FidoNet 2:231/62.58
  32.  
  33. *)
  34.  
  35. Unit PingAnsi;
  36.   {-}
  37. Interface
  38. Uses
  39.  
  40.   { Standard units }
  41.   Dos,
  42.   {$IFDEF TurboPower}
  43.   { Turbo Power units. The standard CRT unit will not work in a TSR }
  44.   TpCrt, TpString;
  45.   {$ELSE}
  46.   { Replacements for Turbo Power units for those unfortunates who doesn't    }
  47.   { have them. It is recommended to buy the Turbo Power toolboxes partly     }
  48.   { because the standard crt unit doesn't stand up too well in a TSR/        }
  49.   { Multitasking environment and partly because they, IMHO, generally make   }
  50.   { life easier for pascal programmers.                                      }
  51.   Crt, PoorMan;
  52.   {$ENDIF}
  53.  
  54. Const
  55.   Title               = 'PingAnsi v1.32 (c) CopyRight P.H.Rankin Hansen 1990.';
  56.  
  57. Var
  58.   Ansi                : Text;     { Ansi is the name of the device }
  59.   Wrap                : Boolean;  { True if Cursor should wrap }
  60.   ReportedX,
  61.   ReportedY           : Word;     { X,Y reported }
  62.  
  63.   { hook for implementing Your own Device Status Report procedure }
  64.   ReplyHook           : Procedure(St : String);
  65.  
  66.   { hook for implementing Your own KeyBoard ReAssignment }
  67.   KeyHook             : Procedure(St : String);
  68.  
  69.   { Hook for handling control chars i.e. Ch < Space }
  70.   WriteHook           : Procedure(Ch : Char);
  71.  
  72.   {$IFNDEF Small}
  73.   {$IFDEF BBS}
  74.  
  75.   { Hook for handling simultaneous writes to ComPort and Screen }
  76.   BBsHook       : Procedure (Ch : Char);
  77.  
  78.   {$ENDIF}
  79.   {$ENDIF}
  80.  
  81.   {$IFDEF Music}
  82.  
  83.   { Hook for handling music }
  84.   PlayHook  : Procedure(St : String);
  85.  
  86.   {$ENDIF}
  87.  
  88. Function In_Ansi    : Boolean;    { True if a sequence is pending }
  89. Procedure AnsiWrite(Ch : Char);
  90.  
  91.   {$IFNDEF Small}
  92.  
  93. Procedure AssignAnsi(Var f : Text); { use like AssignCrt }
  94.  
  95.   {$ENDIF}
  96.  
  97. Implementation
  98.  
  99. Type
  100.   States              = (Waiting, Bracket, Get_Args, Get_Param, Eat_Semi,
  101.                          Get_String, In_Param, Get_Music);
  102. Const
  103.   St                  : String = '';
  104.   ParamArr            : Array[1..10] Of Word = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  105.   Params              : Word = 0; { number of parameters }
  106.   NextState           : States = Waiting; { next state for the parser }
  107.   Reverse             : Boolean = False; { true if text attributes are reversed }
  108.  
  109. Var
  110.   Quote               : Char;
  111.   SavedX, SavedY      : Word;
  112.  
  113.   Function In_Ansi    : Boolean;  { True if a sequence is pending }
  114.   Begin
  115.     In_Ansi := (NextState <> Waiting) And (NextState <> Bracket);
  116.   End {In_Ansi} ;
  117.  
  118.  
  119.   {$F+}
  120.   Procedure Report(St : String);
  121.     {$F-}
  122.   Begin
  123.     StuffString(St);
  124.   End;
  125.  
  126.   {$F+}
  127.   Procedure WriteChar(Ch : Char);
  128.     {$F-}
  129.   Begin
  130.     Case Ch Of
  131.       #7 :
  132.         Begin
  133.           NoSound;
  134.           Sound(500);
  135.           Delay(50);
  136.           NoSound;
  137.           Delay(50);
  138.         End;
  139.       #8 : If (WhereX > 1) Then Write(#8' '#8);
  140.       #9 : If (WhereX < 71) Then
  141.            Repeat
  142.              GotoXy(WhereX + 1, Wherey);
  143.            Until (WhereX Mod 8 = 1);
  144.       Else
  145.         Write(Ch);
  146.     End {Case} ;
  147.   End {WriteChar} ;
  148.  
  149.   {$F+}
  150.   Procedure Dummy(St : String);
  151.     {$F-}
  152.   Begin
  153.   End;
  154.  
  155.   Procedure AnsiWrite(Ch : Char);
  156.  
  157.   Var
  158.     i                   : Word;
  159.  
  160.   Label Command;
  161.  
  162.   Begin
  163.     If Ch = #27 Then
  164.     Begin
  165.       NextState := Bracket;
  166.       Exit;
  167.     End;
  168.     Case NextState Of
  169.       Waiting : If (Ch > ' ') Then Write(Ch)
  170.                 Else WriteHook(Ch);
  171.       Bracket :
  172.         Begin
  173.           If Ch <> '[' Then
  174.           Begin
  175.             NextState := Waiting;
  176.             If (Ch > ' ') Then Write(Ch)
  177.             Else WriteHook(Ch);
  178.             Exit;
  179.           End;
  180.           St := '';
  181.           Params := 1;
  182.           FillChar(ParamArr, 10, 0);
  183.           NextState := Get_Args;
  184.         End;
  185.       Get_Args, Get_Param, Eat_Semi :
  186.         Begin
  187.           {$IFNDEF Music}
  188.           If (NextState = Get_Args) And ((Ch = '=') Or (Ch = '?')) Then
  189.           Begin
  190.             NextState := Get_Param;
  191.             Exit;
  192.           End;
  193.           {$ELSE}
  194.           If (NextState = Get_Args) Then
  195.             Case Ch Of
  196.               '=', '?' :
  197.                 Begin
  198.                   NextState := Get_Param;
  199.                   Exit;
  200.                 End;
  201.               'M' :
  202.                 Begin
  203.                   NextState := Get_Music;
  204.                   Exit;
  205.                 End;
  206.             End {Case} ;
  207.           {$ENDIF}
  208.           If (NextState = Eat_Semi) And (Ch = ';') Then
  209.           Begin
  210.             If Params < 10 Then Inc(Params);
  211.             NextState := Get_Param;
  212.             Exit;
  213.           End;
  214.           Case Ch Of
  215.             '0'..'9' :
  216.               Begin
  217.                 ParamArr[Params] := Ord(Ch) - Ord('0');
  218.                 NextState := In_Param;
  219.               End;
  220.             ';' :
  221.               Begin
  222.                 If Params < 10 Then Inc(Params);
  223.                 NextState := Get_Param;
  224.               End;
  225.             '"', '''' :
  226.               Begin
  227.                 Quote := Ch;
  228.                 St := St + Ch;
  229.                 NextState := Get_String;
  230.               End;
  231.             Else
  232.               GoTo Command;
  233.           End {Case Ch} ;
  234.         End;
  235.       Get_String :
  236.         Begin
  237.           St := St + Ch;
  238.           If Ch <> Quote
  239.           Then NextState := Get_String
  240.           Else NextState := Eat_Semi;
  241.         End;
  242.       In_Param :                  { last char was a digit }
  243.         Begin
  244.           { looking for more digits, a semicolon, or a command char }
  245.           Case Ch Of
  246.             '0'..'9' :
  247.               Begin
  248.                 ParamArr[Params] := ParamArr[Params] * 10 + Ord(Ch) - Ord('0');
  249.                 NextState := In_Param;
  250.                 Exit;
  251.               End;
  252.             ';' :
  253.               Begin
  254.                 If Params < 10 Then Inc(Params);
  255.                 NextState := Eat_Semi;
  256.                 Exit;
  257.               End;
  258.           End {Case Ch} ;
  259. Command:
  260.           NextState := Waiting;
  261.           Case Ch Of
  262.             { Note: the order of commands is optimized for execution speed }
  263.             'm' :                 {sgr}
  264.               Begin
  265.                 For i := 1 To Params Do
  266.                 Begin
  267.                   If Reverse Then TextAttr := TextAttr Shr 4 + TextAttr Shl 4;
  268.                   Case ParamArr[i] Of
  269.                     0 :
  270.                       Begin
  271.                         Reverse := False;
  272.                         TextAttr := 7;
  273.                       End;
  274.                     1 : TextAttr := TextAttr And $FF Or $08;
  275.                     2 : TextAttr := TextAttr And $F7 Or $00;
  276.                     4 : TextAttr := TextAttr And $F8 Or $01;
  277.                     5 : TextAttr := TextAttr Or $80;
  278.                     7 : If Not Reverse Then
  279.                         Begin
  280.                       {
  281.                       TextAttr := TextAttr shr 4 + TextAttr shl 4;
  282.                       }
  283.                           Reverse := True;
  284.                         End;
  285.                     22 : TextAttr := TextAttr And $F7 Or $00;
  286.                     24 : TextAttr := TextAttr And $F8 Or $04;
  287.                     25 : TextAttr := TextAttr And $7F Or $00;
  288.                     27 : If Reverse Then
  289.                          Begin
  290.                            Reverse := False;
  291.                       {
  292.                       TextAttr := TextAttr shr 4 + TextAttr shl 4;
  293.                       }
  294.                          End;
  295.                     30 : TextAttr := TextAttr And $F8 Or $00;
  296.                     31 : TextAttr := TextAttr And $F8 Or $04;
  297.                     32 : TextAttr := TextAttr And $F8 Or $02;
  298.                     33 : TextAttr := TextAttr And $F8 Or $06;
  299.                     34 : TextAttr := TextAttr And $F8 Or $01;
  300.                     35 : TextAttr := TextAttr And $F8 Or $05;
  301.                     36 : TextAttr := TextAttr And $F8 Or $03;
  302.                     37 : TextAttr := TextAttr And $F8 Or $07;
  303.                     40 : TextAttr := TextAttr And $8F Or $00;
  304.                     41 : TextAttr := TextAttr And $8F Or $40;
  305.                     42 : TextAttr := TextAttr And $8F Or $20;
  306.                     43 : TextAttr := TextAttr And $8F Or $60;
  307.                     44 : TextAttr := TextAttr And $8F Or $10;
  308.                     45 : TextAttr := TextAttr And $8F Or $50;
  309.                     46 : TextAttr := TextAttr And $8F Or $30;
  310.                     47 : TextAttr := TextAttr And $8F Or $70;
  311.                   End {Case} ;
  312.                   { fixup for reverse }
  313.                   If Reverse Then TextAttr := TextAttr Shr 4 + TextAttr Shl 4;
  314.                 End;
  315.               End;
  316.             'A' :                 {cuu}
  317.               Begin
  318.                 If ParamArr[1] = 0 Then ParamArr[1] := 1;
  319.                 If (Wherey - ParamArr[1] >= 1)
  320.                 Then GotoXy(WhereX, Wherey - ParamArr[1])
  321.                 Else GotoXy(WhereX, 1);
  322.               End;
  323.             'B' :                 {cud}
  324.               Begin
  325.                 If ParamArr[1] = 0 Then ParamArr[1] := 1;
  326.                 If (Wherey + ParamArr[1] <= Hi(WindMax) - Hi(WindMin) + 1)
  327.                 Then GotoXy(WhereX, Wherey + ParamArr[1])
  328.                 Else GotoXy(WhereX, Hi(WindMax) - Hi(WindMin) + 1);
  329.               End;
  330.             'C' :                 {cuf}
  331.               Begin
  332.                 If ParamArr[1] = 0 Then ParamArr[1] := 1;
  333.                 If (WhereX + ParamArr[1] <= Lo(WindMax)  - Lo(WindMin) + 1)
  334.                 Then GotoXy(WhereX + ParamArr[1], Wherey)
  335.                 Else GotoXy(Lo(WindMax) - Lo(WindMin) + 1, Wherey);
  336.               End;
  337.             'D' :                 {cub}
  338.               Begin
  339.                 If (ParamArr[1] = 0) Then ParamArr[1] := 1;
  340.                 If (WhereX - ParamArr[1] >= 1)
  341.                 Then GotoXy(WhereX - ParamArr[1], Wherey)
  342.                 Else GotoXy(1, Wherey);
  343.               End;
  344.             'H', 'f' :            {cup,hvp}
  345.               Begin
  346.                 If (ParamArr[1] = 0) Then ParamArr[1] := 1;
  347.                 If (ParamArr[2] = 0) Then ParamArr[2] := 1;
  348.  
  349.                 If (ParamArr[2] > Lo(WindMax) + 1)
  350.                   then ParamArr[2] := Lo(WindMax) - Lo(WindMin) + 1;
  351.                 If (ParamArr[1] > Hi(WindMax) + 1)
  352.                   then ParamArr[1] := Hi(WindMax) - Hi(WindMin) + 1;
  353.                 GotoXy(ParamArr[2], ParamArr[1]) ;
  354.               End;
  355.             'J' :                 {EID}
  356.               Case ParamArr[1] Of
  357.                 2 : ClrScr;
  358.                 0 :               {ClrEos}
  359.                   Begin
  360.                     ClrEol;
  361.                     ScrollWindowDown(Lo(WindMin) + 1, Hi(WindMin) + Wherey + 1,
  362.                                      Lo(WindMax) + 1, Hi(WindMax) + 1, 0);
  363.                   End;
  364.                 1 :               {Clear from beginning of screen}
  365.                   Begin
  366.                     ScrollWindowDown(Lo(WindMin) + 1, Hi(WindMin) + Wherey,
  367.                                      Lo(WindMin) + WhereX,
  368.                                      Hi(WindMin) + Wherey, 0);
  369.                     ScrollWindowDown(Lo(WindMin) + 1, Hi(WindMin) + 1,
  370.                                      Lo(WindMax) + 1, Hi(WindMin) + Wherey - 1, 0);
  371.                   End;
  372.               End {Case} ;
  373.             'K' :                 {eil}
  374.               Case ParamArr[1] Of
  375.                 0 : ClrEol;
  376.                 1 :               { clear from beginning of line to cursor }
  377.                   ScrollWindowDown(Lo(WindMin) + 1, Hi(WindMin) + Wherey,
  378.                                    Lo(WindMin) + WhereX - 1,
  379.                                    Hi(WindMin) + Wherey, 0);
  380.                 2 :               { clear entire line }
  381.                   ScrollWindowDown(Lo(WindMin) + 1, Hi(WindMin) + Wherey,
  382.                                    Lo(WindMax) + 1,
  383.                                    Hi(WindMin) + Wherey, 0);
  384.               End {Case ParamArr} ;
  385.             'L' : {il } For i := 1 To ParamArr[1] Do InsLine; { must not move cursor }
  386.             'M' : {d_l} For i := 1 To ParamArr[1] Do DelLine; { must not move cursor }
  387.             'P' :                 {dc }
  388.               Begin
  389.               End;
  390.             'R' :                 {cpr}
  391.               Begin
  392.                 ReportedY := ParamArr[1];
  393.                 ReportedX := ParamArr[2];
  394.               End;
  395.             '@' :                 {ic}
  396.               Begin
  397.                 { insert blank chars }
  398.               End;
  399.             'h', 'l' :            {sm/rm}
  400.               Case ParamArr[1] Of
  401.                 0 : TextMode(BW40);
  402.                 1 : TextMode(CO40);
  403.                 2 : TextMode(BW80);
  404.                 3 : TextMode(CO80);
  405.                 4 : {GraphMode(320x200 col)} ;
  406.                 5 : {GraphMode(320x200 BW)} ;
  407.                 6 : {GraphMode(640x200 BW)} ;
  408.                 7 : Wrap := Ch = 'h';
  409.               End {case} ;
  410.             'n' :                 {dsr}
  411.               If (ParamArr[1] = 6) Then
  412.                 ReplyHook(#27'[' + Long2str(Wherey) + ';' +
  413.                           Long2str(WhereX) + 'R');
  414.             's' :                 {scp}
  415.               Begin
  416.                 SavedX := WhereX;
  417.                 SavedY := Wherey;
  418.               End;
  419.             'u' : {rcp} GotoXy(SavedX, SavedY);
  420.             'p' :                 {keyboard reassignment}
  421.               KeyHook(St);
  422.             Else
  423.               Begin
  424.                 If (Ch > ' ') Then Write(Ch)
  425.                 Else WriteHook(Ch);
  426.                 Exit;
  427.               End;
  428.           End {Case Ch} ;
  429.         End;
  430.       {$IFDEF Music}
  431.       Get_Music :
  432.         Begin
  433.           If Ch <> #3             {Ctrl-C}
  434.           Then St := St + Ch
  435.           Else
  436.           Begin
  437.             NextState := Waiting;
  438.             PlayHook(St);
  439.           End;
  440.         End;
  441.       {$ENDIF}
  442.     End {Case NextState} ;
  443.   End {AnsiWrite} ;
  444.  
  445.   {$IFNDEF Small}
  446.  
  447.   {$F+}                           { All Driver function must be far }
  448.  
  449.   Function Nothing(Var f : TextRec) : Integer;
  450.   Begin
  451.     Nothing := 0;
  452.   End {Nothing} ;
  453.  
  454.   Procedure Null(Ch : Char);
  455.   Begin
  456.     {}
  457.   End {Null} ;
  458.  
  459.   Function DevOutput(Var f : TextRec) : Integer;
  460.   Var
  461.     i                   : Integer;
  462.   Begin
  463.     With f Do
  464.     Begin
  465.       { f.BufPos contains the number of chars in the buffer }
  466.       { f.BufPtr^ is your buffer                            }
  467.       { Any variable conversion done by writeln is already  }
  468.       { done by now.                                        }
  469.       i := 0;
  470.       While i < BufPos Do
  471.       Begin
  472.         AnsiWrite(BufPtr^[i]);
  473.         {$IFDEF BBS}
  474.         BBSHook(BufPtr^[i]);
  475.         {$ENDIF}
  476.         Inc(i);
  477.       End;
  478.       BufPos := 0;
  479.     End;
  480.     DevOutput := 0;               { return IOResult Error codes here }
  481.   End {DevOutput} ;
  482.  
  483.   Function DevOpen(Var f : TextRec) : Integer;
  484.   Begin
  485.     With f Do
  486.     Begin
  487.       If Mode = FmInput Then
  488.       Begin
  489.         InOutFunc := @Nothing;
  490.         FlushFunc := @Nothing;
  491.       End
  492.       Else
  493.       Begin
  494.         Mode := FmOutput;         { in case it was FmInOut }
  495.         InOutFunc := @DevOutput;
  496.         FlushFunc := @DevOutput;
  497.       End;
  498.       CloseFunc := @Nothing;
  499.     End;
  500.     DevOpen := 0;                 { return IOResult error codes here }
  501.   End {DevOpen} ;
  502.  
  503.   Procedure AssignAnsi(Var f : Text);
  504.   Begin
  505.     FillChar(f, SizeOf(f), #0);   { init file var }
  506.     With TextRec(f) Do
  507.     Begin
  508.       Handle := $ffff;
  509.       Mode := FmClosed;
  510.       BufSize := SizeOf(Buffer);
  511.       BufPtr := @Buffer;
  512.       OpenFunc := @DevOpen;
  513.       Name[0] := #0;
  514.     End;
  515.   End {AssignAnsi} ;
  516.   {$ENDIF}
  517.  
  518. Begin
  519.  
  520.   {$IFNDEF Small}
  521.  
  522.   AssignAnsi(Ansi);               { set up the variable }
  523.   Rewrite(Ansi);                  { open it for output  }
  524.  
  525.   {$IFDEF BBS}
  526.  
  527.     BBsHook := Null;
  528.  
  529.   {$ENDIF}
  530.   {$ENDIF}
  531.  
  532.   Wrap := True;
  533.   ReplyHook := Report;
  534.   KeyHook := Dummy;
  535.   WriteHook := WriteChar;
  536.  
  537.   {$IFDEF Music}
  538.  
  539.   PlayHook := Dummy; { point play into the great music heaven }
  540.  
  541.   {$ENDIF}
  542. End.
  543.